package com.miaoxun.dao.util;

import com.miaoxun.common.util.DateUtils;
import com.miaoxun.common.util.JsonUtil;
import com.miaoxun.common.util.Underline2Camel;
import com.miaoxun.domain.annotation.FieldAlias;
import com.miaoxun.domain.annotation.TableAlias;
import org.apache.poi.ss.formula.functions.T;

import javax.persistence.Id;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

public class ClassUtil {


    /**
     * 获取同一路径下所有子类或接口实现类
     *
     * @param cls
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException,
            ClassNotFoundException {
        List<Class<?>> classes = new ArrayList<>();
        for (Class<?> c : getClasses(cls)) {
            if (cls.isAssignableFrom(c) && !cls.equals(c)) {
                classes.add(c);
            }
        }
        return classes;
    }

    /**
     * 取得当前类路径下的所有类
     *
     * @param cls
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static List<Class<?>> getClasses(Class<?> cls) throws IOException,
            ClassNotFoundException {
        String pk = cls.getPackage().getName();
        String path = pk.replace('.', '/');
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        URL url = classloader.getResource(path);
        assert url != null;
        return getClasses(new File(url.getFile()), pk);
    }


    /**
     * 迭代查找类
     *
     * @param dir
     * @param pk
     * @return
     * @throws ClassNotFoundException
     */
    private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {
        List<Class<?>> classes = new ArrayList<Class<?>>();
        if (!dir.exists()) {
            return classes;
        }
        for (File f : Objects.requireNonNull(dir.listFiles())) {
            if (f.isDirectory()) {
                classes.addAll(getClasses(f, pk + "." + f.getName()));
            }
            String name = f.getName();
            if (name.endsWith(".class")) {
                classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6)));
            }
        }
        return classes;
    }


    public static Class str2clazz(String entityClass) {
        if (entityClass.endsWith("Model"))
            entityClass = "com.miaoxun.domain.model." + entityClass;
        if (entityClass.endsWith("Param"))
            entityClass = "com.miaoxun.domain.param" + entityClass;
        else
            entityClass = "com.miaoxun.domain.entity." + entityClass;
        try {
            return Class.forName(entityClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return Object.class;
        }
    }


    public static String field2comun(String entityClass) {

        return field2comun(str2clazz(entityClass));

    }

    /**
     * 获取实体类的表名
     *
     * @param entityClass
     * @return
     */
    public static String field2comun(Class<?> entityClass) {

        Field[] fields = entityClass.getDeclaredFields();
        StringBuilder sql = new StringBuilder();
        for (Field field : fields) {
            if ("serialVersionUID".equalsIgnoreCase(field.getName()))
                continue;
            TableAlias tableAlias = field.getAnnotation(TableAlias.class);
            if (tableAlias != null) {
                sql.append(tableAlias.value());
                sql.append(".");
            }
            FieldAlias fieldAlias = field.getAnnotation(FieldAlias.class);
            if (fieldAlias != null) {
                sql.append(fieldAlias.value());
            } else {
                sql.append(Underline2Camel.camel2Underline(field.getName()));
            }
            sql.append(" ");
            sql.append(field.getName());
            sql.append(",");
        }
        return sql.substring(0, sql.length() - 1);
    }


    public static String class2table(Class clazz) {
        String clazzName = clazz.getSimpleName();
        return class2table(clazzName);
    }

    public static String class2table(String clazzName) {

        clazzName = clazzName.substring(0, 1).toLowerCase() + clazzName.substring(1, clazzName.length());

        return Underline2Camel.camel2Underline(clazzName).toLowerCase();
    }

    /**
     * 获取主键
     *
     * @param clazz
     * @return
     */
    public static String GetPrimaryKey(Class clazz) {

        Field[] declaredFields = clazz.getDeclaredFields();


        if (declaredFields == null)
            return "";


        for (Field declaredField : declaredFields) {

            Id id = declaredField.getAnnotation(Id.class);
            if (id != null)
                return Underline2Camel.camel2Underline(declaredField.getName());
        }


        return "";
    }

    /**
     * 获取主键值
     *
     * @param object
     * @return
     */
    public static String GetPrimaryValue(Object object) {
        Field[] declaredFields = object.getClass().getDeclaredFields();


        if (declaredFields == null)
            return "";


        for (Field declaredField : declaredFields) {

            Id id = declaredField.getAnnotation(Id.class);
            if (id != null) {

                try {
                    declaredField.setAccessible(true);
                    return String.valueOf(declaredField.get(object));
                } catch (IllegalAccessException e) {

                }
            }
        }
        return "";
    }

    public static String GetPrimaryKey(String clazzName) {
        return GetPrimaryKey((str2clazz(clazzName)));
    }

    public static Map<String, String> class2update(Object entity, boolean update) {
        Map<String, String> map = new HashMap<>();

        Field[] declaredFields = entity.getClass().getDeclaredFields();

        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);

            if (declaredField.getAnnotation(Id.class) != null && update)
                continue;

            if (declaredField.getName().equalsIgnoreCase("serialVersionUID"))
                continue;
            String key = Underline2Camel.camel2Underline(declaredField.getName());
            try {
                String value = getValue(declaredField, entity);
                if (value == null || value.length() == 0 || "null".equalsIgnoreCase(value))
                    continue;

                map.put(key, value);
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }

        }
        return map;
    }


    public static String getValue(Field field, Object entity) throws Exception {
        Class<?> type = field.getType();
        String str = "";
        field.setAccessible(true);

        switch (type.getSimpleName().toLowerCase()) {
            case "int":
            case "short":
            case "boolean":
            case "char":
            case "byte":
            case "long":
            case "integer":
                str = String.valueOf(field.get(entity));
                break;

            case "date":
                Date date = (Date) field.get(entity);
                str = "'" + String.valueOf(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)) + "'";
                break;
            default:
                if (field.get(entity) == null)
                    return null;
                str = "'" + field.get(entity) + "'";
                break;

        }

        return str;
    }


    public static Map<String, String> obj2map(Object o) {

        String s = JsonUtil.toJSONString(o);

        return JsonUtil.parseObject(s, Map.class);
    }

    public static String keyValue2colmun(String key, Object value) {

        if (key == null || key.length() == 0)
            return "1=1";

        if (value == null)
            return "1=1";

        if (value instanceof String)
            return key + " like " + "'%" + value + "%'";
        if (value instanceof Date) {
            if (key.indexOf("start") != -1)
                return value + ">=" + "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value) + "'";

            if (key.indexOf("end") != -1)
                return value + "<=" + "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value) + "'";
            else
                return value + "=" + "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value) + "'";
        }

        return key + "=" + value;
    }
}
